﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using My.DataAccess.Core;
using NCLCustomerManagement.Common.Exception;
using NCLCustomerManagement.DataTransferObjects.Customer;


namespace NCLCustomerManagement.DataAccess.CustomerRepository
{
    public class CategoryRepository : BaseRepository<CustomerDTO, Customer>, ICustomerRepository
    {
        public IEnumerable<CustomerDTO> GetCustomersByCriteria(int? regionId, int? productCategoryId, string phone, bool isAdmin)
        {
            var customers = UnitOfWork.Table<Customer>().AsEnumerable();

            if (isAdmin)
            {
                if (regionId.HasValue)
                    customers = customers.Where(e => e.Region == regionId);
                if (productCategoryId.HasValue)
                {
                    customers = customers.Where(e =>
                        e.Customer_ProductCategories.Any(f => f.ProductCategoryId == productCategoryId));
                }
                if (!string.IsNullOrEmpty(phone))
                {
                    customers = customers.Where(e => e.Phone == phone);
                }

            }
            else
            {
                customers = customers.Where(e => e.Phone == phone && !string.IsNullOrEmpty(phone));
            }
            return customers.Select(e => ConvertEntityToDTO(e));
        }

        public CustomerDTO ConvertEntityToDTO(Customer entity)
        {
            var customerDto = base.ConvertEntityToDTO(entity);
            if (entity.Region.HasValue)
                customerDto.CustomerRegion = (Region)(entity.Region.Value);
            customerDto.Products = new List<ProductCategoryDTO>();

            var cates = from c in entity.Customer_ProductCategories
                        select c.ProductCategory;
            customerDto.Products = cates
                .Select(e => AutoMapperBuilder.MapSourceToDestination<ProductCategory, ProductCategoryDTO>(e))
                .ToList();

            return customerDto;
        }




        public IEnumerable<ProductCategoryDTO> GetAllCategories()
        {
            return UnitOfWork.Table<ProductCategory>()
                .Select(e => AutoMapperBuilder.MapSourceToDestination<ProductCategory, ProductCategoryDTO>(e))
                .AsEnumerable();
        }


        public void DeleteCustomer(int[] items)
        {
            foreach (int itemId in items)
            {

                var customer = GetCustomerEntity(itemId);
                foreach (var cate in customer.Customer_ProductCategories)
                {
                    UnitOfWork.DeleteOnSubmit<Customer_ProductCategory>(cate);
                }
                foreach (var r in customer.UserRequests)
                {
                    UnitOfWork.DeleteOnSubmit<UserRequest>(r);
                }
                UnitOfWork.DeleteOnSubmit<Customer>(customer);
            }
            UnitOfWork.SubmitChanges();
        }
        private Customer GetCustomerEntity(int id)
        {
            return UnitOfWork.Table<Customer>().SingleOrDefault(e => e.Id == id);
        }



        public void AddNewCustomer(CustomerDTO dto)
        {
            Customer customer = ConvertDTOToEntity(dto);

            foreach (var cate in dto.Products)
            {
                customer.Customer_ProductCategories.Add(new Customer_ProductCategory()
                {
                    Customer = customer,
                    ProductCategoryId = cate.Id
                });
            }
            UnitOfWork.InsertOnSubmit<Customer>(customer);
            UnitOfWork.SubmitChanges();
        }

        protected override Customer ConvertDTOToEntity(CustomerDTO dto)
        {
            var entity = base.ConvertDTOToEntity(dto);
            entity.Region = (int)dto.CustomerRegion;
            return entity;
        }

        public void UpdateCustomer(CustomerDTO dto)
        {
            var customer = GetCustomerEntity(dto.Id);
            if (customer == null)
                throw new EntityNotFoundException("Customer may be deleted");
            customer.CustomerName = dto.CustomerName;
            customer.Address = dto.Address;
            customer.Phone = dto.Phone;
            customer.Region = (int)dto.CustomerRegion;
            customer.LastModifiedDate = dto.LastModifiedDate;
            customer.LastModifiedUser = dto.LastModifiedUser;

            var currentCategories = customer.Customer_ProductCategories
                .Select(e => e.ProductCategory)
                .ToList();

            var justAddedCategories = dto.Products.Select(e => e.Id)
                .Except(currentCategories.Select(e => e.Id));
            var removedCategories = currentCategories.Select(e => e.Id)
                .Except(dto.Products.Select(e => e.Id));

            foreach (var item in justAddedCategories)
            {
                customer.Customer_ProductCategories.Add(new Customer_ProductCategory()
                {
                    Customer = customer,
                    ProductCategoryId = item
                });
            }
            foreach (var item in removedCategories)
            {
                var removeItem = customer.Customer_ProductCategories
                    .SingleOrDefault(e => e.ProductCategoryId == item);
                
                UnitOfWork.DeleteOnSubmit<Customer_ProductCategory>(removeItem);
            }


            UnitOfWork.SubmitChanges();
        }


        public bool CheckProductExist(int productId, int customerId)
        {
            return UnitOfWork.Table<Customer_ProductCategory>()
                .Any(e => e.CustomerId == customerId && e.ProductCategoryId == productId);
        }



        public void RequestChange(CustomerDTO dto, string requester, string requestTo)
        {
            var request = new UserRequest()
            {
                Address = dto.Address,
                AddedProductCategories = string.Join(", ", dto.Products.Select(e => e.Id)),
                Bank = dto.Bank,
                CreditCardNumber = dto.CreditCardNumber,
                CustomerId = dto.Id,
                Notes = dto.Notes,
                Phone = dto.Phone,
                Region = (int)dto.CustomerRegion,
                Requester = requester,
                RequestTo = requestTo,
                CustomerName = dto.CustomerName,
                Status = 0,
                RequestedDate = DateTime.Now
            };

            UnitOfWork.InsertOnSubmit<UserRequest>(request);
            UnitOfWork.SubmitChanges();
        }


        public CustomerDTO GetCustomerById(int id)
        {
            var entity = GetCustomerEntity(id);
            return ConvertEntityToDTO(entity);
        }


        public void AddNewProductCategory(string name)
        {
            UnitOfWork.InsertOnSubmit<ProductCategory>(new ProductCategory() { ProductCategoryName= name });
            UnitOfWork.SubmitChanges();
        }


        public void DeleteProductCategory(int id)
        {
            var entity = UnitOfWork.Table<ProductCategory>().SingleOrDefault(e => e.Id == id);

            foreach (var relative in entity.Customer_ProductCategories)
            {
                UnitOfWork.DeleteOnSubmit<Customer_ProductCategory>(relative);
            }
            
            UnitOfWork.DeleteOnSubmit<ProductCategory>(entity);
            UnitOfWork.SubmitChanges();            
        }


        public void UpdateProductCategory(int id, string name)
        {
            var entity = UnitOfWork.Table<ProductCategory>().SingleOrDefault(e => e.Id == id);
            entity.ProductCategoryName = name;
            UnitOfWork.SubmitChanges();
        }
    }
}
